﻿/*********************************************************
 * 开发人员：小兵
 * 创建时间：2012-10-15 16:03:22
 * 描述说明：
 * 
 * 更改历史：
 * 
 * *******************************************************/
namespace Mozlite.Components
{
    using System;
    using System.Web;
    using System.Data;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Trie算法字符关键字过滤类型。
    /// </summary>
    public class TrieFilter : TrieNode, IWordFilter
    {
        /// <summary>
        /// 添加关键词。
        /// </summary>
        /// <param name="key">关键词。</param>
        public void AddKey(string key)
        {
            if(string.IsNullOrEmpty(key))
            {
                return;
            }
            TrieNode node = this;
            for(int i = 0; i < key.Length; i++)
            {
                char c = key[i].Simplified();
                node = node.Add(c);
            }
            node.IsEnd = true;
        }

        /// <summary>
        /// 判断当前字符串中是否含有关键词。
        /// </summary>
        /// <param name="text">输入的字符串。</param>
        /// <returns>如果存在返回<c>true</c>，否则返回<c>false</c>。</returns>
        public bool HasKey(string text)
        {
            for(int head = 0; head < text.Length; head++)
            {
                int index = head;
                TrieNode node = this;
                while(node.TryGetValue(text[index], out node))
                {
                    if(node.IsEnd)
                    {
                        return true;
                    }
                    if(text.Length == ++index)
                    {
                        break;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 查找并返回第一个关键词。
        /// </summary>
        /// <param name="text">输入的字符串。</param>
        /// <returns>如果存在则返回第一个关键词，否则返回String.Empty。</returns>
        public string Find(string text)
        {
            for(int head = 0; head < text.Length; head++)
            {
                int index = head;
                TrieNode node = this;
                while(node.TryGetValue(text[index].Simplified(), out node))
                {
                    if(node.IsEnd)
                    {
                        return text.Substring(head, index - head + 1);
                    }
                    if(text.Length == ++index)
                    {
                        break;
                    }
                }
            }
            return string.Empty;
        }

        /// <summary>
        /// 查找字符串中所有关键词。
        /// </summary>
        /// <param name="text">输入的字符串。</param>
        /// <returns>返回关键词列表。</returns>
        public List<string> FindAll(string text)
        {
            List<string> result = new List<string>();
            for(int head = 0; head < text.Length; head++)
            {
                int index = head;
                TrieNode node = this;
                while(node.TryGetValue(text[index].Simplified(), out node))
                {
                    if(node.IsEnd)
                    {
                        result.Add(text.Substring(head, index - head + 1));
                    }
                    if(text.Length == ++index)
                    {
                        break;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 执行关键词替换。
        /// </summary>
        /// <param name="text">输入的字符串。</param>
        /// <param name="mask">替换字符。</param>
        /// <returns>返回替换后的字符串。</returns>
        public string Replace(string text, char mask = '*')
        {
            char[] chars = null;
            for(int head = 0; head < text.Length; head++)
            {
                int index = head;
                TrieNode node = this;
                while(node.TryGetValue(text[index].Simplified(), out node))
                {
                    if(node.IsEnd)
                    {
                        if(chars == null)
                            chars = text.ToArray();
                        for(int i = head; i <= index; i++)
                        {
                            chars[i] = mask;
                        }
                        head = index;
                    }
                    if(text.Length == ++index)
                    {
                        break;
                    }
                }
            }
            return chars == null ? text : new string(chars);
        }
    }
}
